package com.lebang.common.validcode;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lebang.common.utils.OkHttpUtil;
import com.lebang.component.RedisClient;
import com.lebang.model.ValidCodeRecord;
import com.lebang.service.sys.DictService;
import com.lebang.service.sys.RegisterWhiteImeiService;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @Author: hwq
 * @Date: 2019/5/17 9:29
 * @Version 1.0
 */
@PropertySource(value = "classpath:/application.yml")
@Service
public class ValidCodeUtil {
    @Autowired
    private ValidCodeRecordService validCodeRecordService;
    private static final Logger log = LoggerFactory.getLogger(ValidCodeUtil.class);
    public static final MediaType JSON_TYPE = MediaType
            .parse("application/json; charset=utf-8");
    @Autowired
    private RedisClient redisClient;
    public static final String U_MENT_PHONE_CODE = "umeng_phone_code";
    public static final String LOG_OUT_CODE = "logout_code:";
    public static final String INVITE_CODE = "invite_code:";
    public static final String DEF_CHATSET = "UTF-8";
    public static final int DEF_CONN_TIMEOUT = 30000;
    public static final int DEF_READ_TIMEOUT = 30000;
    public static String userAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36";
    private static final String CALLADDRESS = "http://v.juhe.cn/sms/send";
    @Autowired
    private DictService dictService;
    @Autowired
    private RegisterWhiteImeiService registerWhiteImeiService;
    private static final Integer PHONE_COUNT = 5;
    @Value("${info.juhe.TPL_ID}")
    private String TPL_ID;
    @Value("${info.juhe.KEY}")
    private String KEY;
    @Value("${info.name}")
    private String APP_NAME;
    @Value("${info.juhe.TPL_LOGOUT_ID}")
    private String TPL_LOGOUT_ID;
    @Value("${info.juhe.TPL_LOGOUT_SUCCESS_ID}")
    private String TPL_LOGOUT_SUCCESS_ID;

    public void cleanPhone(String phone) {
        redisClient.hdel(U_MENT_PHONE_CODE, phone);
    }

    //发送短信注册
    public ValidCodeStatus getValidCode(String mobile, ValidCodeRecord record) {

        //验证设备号和ip的每日个数是否大于5
        if (!registerWhiteImeiService.getImei(record.getImei())) {
            //不是白名单进行设备号和ip校验
            LocalDateTime star = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
            LocalDateTime end = LocalDateTime.now();
            if(validCodeRecordService.countValidImeiNum(star,end,record.getImei())>=5){
                return new ValidCodeStatus(false, "", record.getImei(), "该设备当天已发送5次");
            }
            if(validCodeRecordService.countValidIpAddrNum(star,end,record.getIpAddr())>=5){
                return new ValidCodeStatus(false, "", record.getIpAddr(), "当前网络当天已发送5次");
            }
        }

        String tplId = "";
        if ("兼职咸鱼".equals(APP_NAME) && "huawei".equals(record.getAppStore())) {
            tplId = dictService.selectByKeyName("xianyu_huawei_phone_code").getKeyvalue();
        } else {
            tplId = TPL_ID;
        }
        String str = redisClient.hget(U_MENT_PHONE_CODE, mobile);

        Integer count = str == null ? 0 : Integer.parseInt(str);

        if (count >= PHONE_COUNT) {
            return new ValidCodeStatus(false, "", mobile, "发送失败!该手机号当天已发送5次");
        }
        String icode = Maths.random(1000, 9999).toString();
        String codef = String.format("#code#=%s", icode);
        System.out.println(codef);
        try {
            record.setPhone(mobile);
            record.setCode(icode);
            validCodeRecordService.insertRecord(record);
            String result = null;
            Map params = new HashMap();
            //请求参数
            params.put("mobile", mobile);
            //接收短信的手机号码
            params.put("tpl_id", tplId);
            //短信模板ID，请参考个人中心短信模板设置
            params.put("tpl_value", URLEncoder.encode(codef, "utf-8"));
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", KEY);
            //应用APPKEY(应用详细页查询)
            result = net(CALLADDRESS, params, "GET");
            JSONObject object = JSON.parseObject(result);
            if (object.getIntValue("error_code") == 0) {
                log.info(object.get("result").toString());
                //用户当天发送次数+1
                Integer newCount = count + 1;
                redisClient.hset(U_MENT_PHONE_CODE, mobile, newCount.toString());
                return new ValidCodeStatus(true, icode, mobile, "发送成功");

            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new ValidCodeStatus(false, "", mobile, object.get("reason").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ValidCodeStatus(false, "", mobile, "系统错误");
        }
    }


    //发送短信验证注销
    public ValidCodeStatus getLogoutValidCode(String mobile, ValidCodeRecord record) {
        LocalDate nowDate = LocalDate.now();
        String tplId = "";
        if ("兼职咸鱼".equals(APP_NAME) && "huawei".equals(record.getAppStore())) {
            tplId = dictService.selectByKeyName("xianyu_huawei_phone_code").getKeyvalue();
        } else {
            tplId = TPL_LOGOUT_ID;
        }
        String str = redisClient.hget(LOG_OUT_CODE+nowDate.format(DateTimeFormatter.ISO_DATE), mobile);

        Integer count = str == null ? 0 : Integer.parseInt(str);

        if (count >= 5) {
            return new ValidCodeStatus(false, "", mobile, "发送失败!该手机号当天已发送5次");
        }
        String icode = Maths.random(1000, 9999).toString();
        String codef = String.format("#code#=%s", icode);
        try {
            record.setPhone(mobile);
            record.setCode(icode);
            validCodeRecordService.insertRecord(record);
            String result = null;
            Map params = new HashMap();
            //请求参数
            params.put("mobile", mobile);
            //接收短信的手机号码
            params.put("tpl_id", tplId);
            //短信模板ID，请参考个人中心短信模板设置
            params.put("tpl_value", URLEncoder.encode(codef, "utf-8"));
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", KEY);
            //应用APPKEY(应用详细页查询)
            result = net(CALLADDRESS, params, "GET");
            JSONObject object = JSON.parseObject(result);
            if (object.getIntValue("error_code") == 0) {
                log.info(object.get("result").toString());
                //用户当天发送次数+1
                Integer newCount = count + 1;
                redisClient.hset(LOG_OUT_CODE+nowDate.format(DateTimeFormatter.ISO_DATE), mobile, newCount.toString());
                //过期时间修改注释
                //redisClient.expire(LOG_OUT_CODE+nowDate.format(DateTimeFormatter.ISO_DATE),24*60*60);
                return new ValidCodeStatus(true, icode, mobile, "发送成功");

            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new ValidCodeStatus(false, "", mobile, object.get("reason").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ValidCodeStatus(false, "", mobile, "系统错误");
        }
    }

    //发送短信通知注销
    public ValidCodeStatus getLogoutSuccess(String mobile) {
        String tplId = TPL_LOGOUT_SUCCESS_ID;

        String icode = Maths.random(1000, 9999).toString();
        String codef = String.format("#code#=%s", icode);
        try {
            String result = null;
            Map params = new HashMap();
            //请求参数
            params.put("mobile", mobile);
            //接收短信的手机号码
            params.put("tpl_id", tplId);
            //短信模板ID，请参考个人中心短信模板设置
            params.put("tpl_value", URLEncoder.encode(codef, "utf-8"));
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", KEY);
            //应用APPKEY(应用详细页查询)
            result = net(CALLADDRESS, params, "GET");
            JSONObject object = JSON.parseObject(result);
            if (object.getIntValue("error_code") == 0) {
                log.info(object.get("result").toString());
                return new ValidCodeStatus(true, icode, mobile, "发送成功");

            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new ValidCodeStatus(false, "", mobile, object.get("reason").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ValidCodeStatus(false, "", mobile, "系统错误");
        }
    }


    //发送邀请短信注册
    public ValidCodeStatus getInviteValidCode(String mobile, ValidCodeRecord record) {
        String tplId = "";
        if ("兼职咸鱼".equals(APP_NAME) && "huawei".equals(record.getAppStore())) {
            tplId = dictService.selectByKeyName("xianyu_huawei_phone_code").getKeyvalue();
        } else {
            tplId = TPL_ID;
        }
        String str = redisClient.hget(INVITE_CODE, mobile);

        Integer count = str == null ? 0 : Integer.parseInt(str);

        if (count >= PHONE_COUNT) {
            return new ValidCodeStatus(false, "", mobile, "发送失败!该手机号当天已发送5次");
        }
        String icode = Maths.random(1000, 9999).toString();
        String codef = String.format("#code#=%s", icode);
        try {
            record.setPhone(mobile);
            record.setCode(icode);
            validCodeRecordService.insertRecord(record);
            String result = null;
            Map params = new HashMap();
            //请求参数
            params.put("mobile", mobile);
            //接收短信的手机号码
            params.put("tpl_id", tplId);
            //短信模板ID，请参考个人中心短信模板设置
            params.put("tpl_value", URLEncoder.encode(codef, "utf-8"));
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", KEY);
            //应用APPKEY(应用详细页查询)
            result = net(CALLADDRESS, params, "GET");
            JSONObject object = JSON.parseObject(result);
            if (object.getIntValue("error_code") == 0) {
                log.info(object.get("result").toString());
                //用户当天发送次数+1
                Integer newCount = count + 1;
                redisClient.hset(INVITE_CODE, mobile, newCount.toString());
                return new ValidCodeStatus(true, icode, mobile, "发送成功");

            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new ValidCodeStatus(false, "", mobile, object.get("reason").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ValidCodeStatus(false, "", mobile, "系统错误");
        }
    }


    //发送短信
    public ValidCodeStatus sendMsg(String mobile, String tplId, String tplVaue, String tplVar) {

        String icode = tplVaue;
        String codef = String.format("#" + tplVar + "#=%s", icode);
        try {
            String result = null;
            Map params = new HashMap();
            //请求参数
            params.put("mobile", mobile);
            //接收短信的手机号码
            params.put("tpl_id", tplId);
            //短信模板ID，请参考个人中心短信模板设置
            params.put("tpl_value", URLEncoder.encode(codef, "utf-8"));
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", "dc352ed5126683c0d4a1f5ec69638d17");
            //应用APPKEY(应用详细页查询)
            result = net(CALLADDRESS, params, "GET");
            JSONObject object = JSON.parseObject(result);
            if (object.getIntValue("error_code") == 0) {
                log.info(object.get("result").toString());
                return new ValidCodeStatus(true, icode, mobile, "发送成功");
            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new ValidCodeStatus(false, "", mobile, object.get("reason").toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ValidCodeStatus(false, "", mobile, "系统错误");
        }
    }

    private static final String MSG = "{\n" +
            "    \"account\":\"IM4217001\",\n" +
            "    \"password\":\"euhafkp0I\", \n" +
            "    \"msg\":\"{msg}\",\n" +
            "    \"mobile\":\"{phone}\"\n" +
            "}";
    private static final String CL_URL = "http://intapi.253.com/send";

    //发送短信
    public void sendMsgByCl(String mobile, String appName, String money) {
        String str = dictService.selectByKeyName("cl_msg_mrbz").getKeyvalue();
        str = str.replace("{appName}", appName);
        str = str.replace("{money}", money);
        str = MSG.replace("{msg}", str);
        str = str.replace("{phone}", "0086" + mobile);
        //System.out.println(str);
        doPostHttpRequest(CL_URL, str);
    }

//    public static void main(String[] args) throws IOException {
//        String str = "{\n" +
//                "    \"account\":\"IM4217001\",\n" +
//                "    \"password\":\"euhafkp0I\", \n" +
//                "    \"msg\":\"【兼职咸鱼】亲爱的用户，您的签到任务【{appName}】今日可签，完成即得【{money}】 回T退订\",\n" +
//                "    \"mobile\":\"008613163997957\"\n" +
//                "}";
//        doPostHttpRequest("http://intapi.253.com/send", str);
//    }

    /**
     * 根据url地址和json数据获取数据
     *
     * @param url
     * @param json
     * @return
     * @throws IOException
     */
    public void doPostHttpRequest(String url, String json) {
        Request request = new Request.Builder().url(url)
                .post(RequestBody.create(JSON_TYPE, json)).build();

        Response response = null;
        try {
            response = OkHttpUtil.getInstance().newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (response != null && !response.isSuccessful()) {
            //  System.out.println("短信通知签到失败");
        }
    }

    /**
     * @param strUrl 请求地址
     * @param params 请求参数
     * @param method 请求方法
     * @return 网络请求字符串
     * @throws Exception
     */
    public static String net(String strUrl, Map params, String method) throws Exception {
        HttpURLConnection conn = null;
        BufferedReader reader = null;
        String rs = null;
        try {
            StringBuffer sb = new StringBuffer();
            if (method == null || "GET".equals(method)) {
                strUrl = strUrl + "?" + urlencode(params);
            }
            URL url = new URL(strUrl);
            conn = (HttpURLConnection) url.openConnection();
            if (method == null || "GET".equals(method)) {
                conn.setRequestMethod("GET");
            } else {
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
            }
            conn.setRequestProperty("User-agent", userAgent);
            conn.setUseCaches(false);
            conn.setConnectTimeout(DEF_CONN_TIMEOUT);
            conn.setReadTimeout(DEF_READ_TIMEOUT);
            conn.setInstanceFollowRedirects(false);
            conn.connect();
            if (params != null && "POST".equals(method)) {
                try {
                    DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                    out.writeBytes(urlencode(params));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            InputStream is = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sb.append(strRead);
            }
            rs = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        return rs;
    }

    //将map型转为请求参数型
    public static String urlencode(Map<String, Object> data) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry i : data.entrySet()) {
            try {
                sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue() + "", "UTF-8")).append("&");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }


    public boolean checkCode(String phone, RedisLogin redisLogin, String code) {
        String str = redisClient.get(redisLogin.getName() + phone);
        if (str == null) {
            return false;
        }
        if (str.equals(code)) {

            return true;
        } else {
            return false;
        }
    }

    public void cleanCode(String phone, RedisLogin redisLogin, String code) {
        redisClient.del(redisLogin.getName() + phone);
    }

    private static final String ID_CRAD_URL = "http://op.juhe.cn/idcard/query";
    public static final String ID_CARD_COUNT = "ID_CARD_COUNT";

    public IdCardStatus checkIdCard(String name, String idCard, String mobile) {
        if(dictService.selectIntByKeyName("open_idcard_filter")==1){
            return new IdCardStatus(true, name, idCard, "验证通过");
        }
        Optional<String> str = redisClient.Optionalhget(ID_CARD_COUNT, mobile);

        Integer count = str.map(Integer::parseInt).orElse(0);

        if (count >= dictService.selectIntByKeyName("juhe_idcard_count")) {
            return new IdCardStatus(false, "", "", "发送失败!该手机号本周检查次数达到上限");
        }

        try {
            Map<String,String> params = new HashMap(1);
            //请求参数
            params.put("idcard", idCard);
            //接收短信的手机号码
            params.put("realname", name);

            //短信模板ID，请参考个人中心短信模板设置
            params.put("orderid", "1");
            //变量名和变量值对。如果你的变量名或者变量值中带有#&=中的任意一个特殊符号，请先分别进行urlencode编码后再传递，<a href="http://www.juhe.cn/news/index/id/50" target="_blank">详细说明></a>
            params.put("key", "d3b4f51bd4f0eeb62b946feb614039f1");
            //应用APPKEY(应用详细页查询)
            JSONObject object = OkHttpUtil.postRequest(ID_CRAD_URL, params);
            if (object!=null&&object.getIntValue("error_code") == 0) {
                boolean status = object.getJSONObject("result").getInteger("res").equals(1);
                //用户当天发送次数+1
                redisClient.hincrby(ID_CARD_COUNT, mobile, 1L);
                return new IdCardStatus(status,
                        object.getJSONObject("result").getString("realname"),
                        object.getJSONObject("result").getString("idcard"),
                        status ?"验证通过":"身份信息不匹配");
            } else {
                log.info(object.get("error_code") + ":" + object.get("reason"));
                return new IdCardStatus(false,
                        "",
                        "",
                        object.getString("reason"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new IdCardStatus(false, "", mobile, "系统错误");
        }
    }
}
